#ifndef _RING_QUEUE_HPP_
#define _RING_QUEUE_HPP_

#include <iostream>
#include <vector>
#include <pthread.h>
#include <unistd.h>
#include "Sem.hpp"
#include "Task.hpp"

using namespace std;

const int g_default_num = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(int default_num = g_default_num)
        :_ring_queue(default_num)
        ,_num(default_num)
        ,_c_step(0)
        ,_p_step(0)
        ,_space_sem(default_num)
        ,_data_sem(0)
    {
        pthread_mutex_init(&_clock, nullptr);
        pthread_mutex_init(&_plock, nullptr);
    }
    ~RingQueue()
    {
        pthread_mutex_destroy(&_clock);
        pthread_mutex_destroy(&_plock);
    }
    // 生产者
    void push(const T& in)
    {
        _space_sem.P();
        pthread_mutex_lock(&_plock);
        _ring_queue[_p_step++] = in;
        _p_step %= _num;
        pthread_mutex_unlock(&_plock);
        _data_sem.V();
    }
    // 消费者
    void pop(T* out)
    {
        _data_sem.P();
        pthread_mutex_lock(&_clock);
        *out = _ring_queue[_c_step++];
        _c_step %= _num;
        pthread_mutex_unlock(&_clock);
        _space_sem.V();
    }
    void debug()
    {
        cout << "size: " << _num << "queue: " << _ring_queue.size() << endl;
    }

private:
    vector<T> _ring_queue;
    size_t _num;
    int _c_step; // 消费者下标
    int _p_step; // 生产者下标
    Sem _space_sem; // 空间信号量
    Sem _data_sem; // 数据信号量
    pthread_mutex_t _clock; // 消费者之间的锁
    pthread_mutex_t _plock; // 生产者之间的锁
};


#endif 